home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 476-500 / disk_500 / wiconify / wiconify-source.lzh / Source / wFileRead.c < prev    next >
C/C++ Source or Header  |  1991-04-19  |  21KB  |  710 lines

  1. /*
  2.  *  WICONIFY    A utility that allows you to iconify any Intuition window
  3.  *              on any screen, and to open WB windows on any screen.
  4.  *
  5.  *  wFileRead.c     Performs most of the structured file IO.
  6.  *
  7.  *  Copyright 1990 by Davide P. Cervone, all rights reserved.
  8.  *  You may use this code, provided this copyright notice is kept intact.
  9.  */
  10.  
  11. #include "wFile.h"
  12. #include "wMenu.h"
  13.  
  14.  
  15. extern int ScreenType;
  16. extern UWORD ImageData[MAXWORDS][MAXHEIGHT][MAXDEPTH]; 
  17. extern short MaxWidth,MaxHeight,MaxWords;
  18. extern UBYTE Plane0,Plane1;
  19. extern int ImageType;
  20. extern int IconFileOpen;
  21. static int NoMaskError;             /* FALSE if a mask error was reported */
  22. static short ErrorCount;            /* number of error messages so far */
  23.  
  24. #define MAXERROR    8               /* maximum number of errors in a line */
  25.  
  26. /*
  27.  *  Macros for working with HEX and Color values
  28.  */
  29.  
  30. #define HEXCHAR(c)      (((c)>='0'&&(c)<='9')||((c)>='A'&&(c)<='F'))
  31. #define VALIDCOLOR(w)\
  32.    (HEXCHAR(w[0])&&HEXCHAR(w[1])&&HEXCHAR(w[2])&&w[3]==0)
  33.  
  34. #define HEX(c)          (((c)>'9')?(c)-'A'+10:(c)-'0')
  35. #define RGB(r,g,b)      ((r<<8)|(g<<4)|b)
  36. #define COLOR(w)        RGB(HEX(w[0]),HEX(w[1]),HEX(w[2]))
  37.  
  38. /*
  39.  *  Allowable HEX codes
  40.  */
  41.  
  42. static char *ExtHex = "0123456789abcdef)!@#$%^&*(ABCDEF";
  43.  
  44.  
  45. /*
  46.  *  The initialization file command keywords
  47.  */
  48.  
  49. static char *MainCommand[] =
  50. {
  51.    "",                      /* No command given */
  52.    "Iconify_Key",           /* Sets the key and quals that iconify a window */
  53.    "Change_Refresh",        /* Sets the quals that change refresh type */
  54.    "Activation_Key",        /* Sets the key and quals that activate wIconify */
  55.    "Color_Map",             /* Sets the default NewScreen color map */
  56.    "Default_Flags",         /* Sets the default icon's icon flags */
  57.    "Screen_Flags",          /* Sets the default screen icon's icon flags */
  58.    "Menu_Keys",             /* Sets the menu key equivalents */
  59.    "Ignore_Screen",         /* Adds screen titles to be ignored by wIconify */
  60.    "Priority",              /* Sets the wIconify process priority */
  61.    "HiRes_CLICommand",      /* Sets the HIRES NewCLI command string */
  62.    "LoRes_CLICommand",      /* Sets the LOWRES NewCLI command string */
  63.    "Default_Image",         /* Defines the default icon image */
  64.    "Default_Select",        /* Defines the default icon select image */
  65.    "Default_Mask",          /* Defines the default icon image mask */
  66.    "Default_Icon",          /* Reads the default icon from a file */
  67.    "Screen_Image",          /* Defines the default screen icon image */
  68.    "Screen_Select",         /* Defines the default screen icon select image */
  69.    "Screen_Mask",           /* Defines the default screen icon image mask */
  70.    "Screen_Icon",           /* Reads the default screen icon from a file */
  71.    "Open_On",               /* Sets the OpenOn window submenu entries */
  72.    "Size_To_Fit",           /* Sets or clears the SizeToFit option */
  73.    "Command_Stack",         /* Sets the size of the newCLI command stack */
  74.    "Handler_Priority",      /* Sets the Input Device handler priority */
  75. };
  76. #define MAXMAINCOM  COM_LAST
  77.  
  78.  
  79. /*
  80.  *  The commands for within an icon file (for DEFAULT_ICON and SCREEN_ICON)
  81.  */
  82.  
  83. static char *IconCommand[] =
  84. {
  85.    "Image",                 /* Sets the default icon image */
  86.    "Select",                /* Sets the default icon select image */
  87.    "Mask"                   /* Sets the default icon image mask */
  88. };
  89. #define MAXICONCOM  2
  90.  
  91. char **ComName = &MainCommand[0];       /* The current command set */
  92. static int ComOffset;                   /* Add this to get "real" command # */
  93. static int ComCount = MAXMAINCOM;       /* Size of command array */
  94.  
  95.  
  96. /*
  97.  *  Icon Flags for DEFAULT_FLAGS command
  98.  */
  99.  
  100. static struct Flag IconFlag[] =
  101. {
  102.    {"NOICONIFY",    WI_NOICONIFY},      /* Window can not be iconified */
  103.    {"NOSAVEPOS",    WI_NOSAVEPOS},      /* Position not saved when openned */
  104.    {"NOCLOSE",      WI_NOCLOSE},        /* CLOSE menu not available */
  105.    {"NOORGANIZE",   WI_NOORGANIZE},     /* Icon not affected by ORGANIZE */
  106.    {"NOMOVE",       WI_NOMOVE},         /* Icon can not be moved */
  107.    {"LOCKED",       WI_LOCKED},         /* Never change icon X,Y */
  108.    {"NOMULTISELECT",WI_NOMULTISELECT},  /* No more than one icon selectable */
  109.    {"CHANGEREFRESH",WI_CHANGEREFRESH},  /* Automatically change refresh type */
  110. };
  111. #define MAXICONFLAG 8
  112.  
  113.  
  114. /*
  115.  *  Qualifier key names and flags for ReadKeyDefinition()
  116.  */
  117.  
  118. static struct Flag KeyFlag[] =
  119. {
  120.    {"LSHIFT",       IEQUALIFIER_LSHIFT},
  121.    {"RSHIFT",       IEQUALIFIER_RSHIFT},
  122.    {"CAPSLOCK",     IEQUALIFIER_CAPSLOCK},
  123.    {"CONTROL",      IEQUALIFIER_CONTROL},
  124.    {"LALT",         IEQUALIFIER_LALT},
  125.    {"RALT",         IEQUALIFIER_RALT},
  126.    {"LCOMMAND",     IEQUALIFIER_LCOMMAND},
  127.    {"RCOMMAND",     IEQUALIFIER_RCOMMAND},
  128.    {"LAMIGA",       IEQUALIFIER_LCOMMAND},
  129.    {"RAMIGA",       IEQUALIFIER_RCOMMAND},
  130.    {"NUMERICPAD",   IEQUALIFIER_NUMERICPAD},
  131.    {"REPEAT",       IEQUALIFIER_REPEAT},
  132.    {"MBUTTON",      IEQUALIFIER_MIDBUTTON},
  133.    {"RBUTTON",      IEQUALIFIER_RBUTTON},
  134.    {"LBUTTON",      IEQUALIFIER_LEFTBUTTON},
  135. };
  136. #define MAXKEYFLAG  15
  137.  
  138. /*
  139.  *  Key names and numbers for ReadKeyDefinition()
  140.  */
  141.  
  142. #define KEY(x)      (x|IECODE_UP_PREFIX)
  143. struct Flag KeyName[] =
  144. {
  145.    {"RBUTTONPRESS",  MENUUP},
  146.    {"LBUTTONPRESS",  SELECTUP},
  147.    {"F1",       KEY(0x50)},
  148.    {"F2",       KEY(0x51)},
  149.    {"F3",       KEY(0x52)},
  150.    {"F4",       KEY(0x53)},
  151.    {"F5",       KEY(0x54)},
  152.    {"F6",       KEY(0x55)},
  153.    {"F7",       KEY(0x56)},
  154.    {"F8",       KEY(0x57)},
  155.    {"F9",       KEY(0x58)},
  156.    {"F10",      KEY(0x59)},
  157.    {"ESC",      KEY(0x45)},
  158.    {"ENTER",    KEY(0x43)},
  159.    {"RETURN",   KEY(0x44)},
  160.    {"BACKSPACE",KEY(0x41)},
  161.    {"DELETE",   KEY(0x46)},
  162.    {"HELP",     KEY(0x5F)},
  163.    {"TAB",      KEY(0x42)},
  164.    {"SPACE",    KEY(0x40)}
  165. };
  166. #define MAXKEYNAME  20
  167.  
  168.  
  169. /*
  170.  *  Menu names and IDs
  171.  */
  172.  
  173. struct Flag MenuName[] =
  174. {
  175.    {"OPEN",             MENUID(ICON_MENU,IM_OPEN,NOSUB)},
  176.    {"CLOSE",            MENUID(ICON_MENU,IM_CLOSE,NOSUB)},
  177.    {"LOCK",             MENUID(ICON_MENU,IM_LOCK,NOSUB)},
  178.    {"UNLOCK",           MENUID(ICON_MENU,IM_LOCK,NOSUB)},
  179.    {"CLEAN_UP",         MENUID(ICON_MENU,IM_CLEANUP,NOSUB)},
  180.    {"ORGANIZE",         MENUID(ICON_MENU,IM_ORGANIZE,NOSUB)},
  181.    {"OPEN_ALL",         MENUID(ICON_MENU,IM_OPENALL,NOSUB)},
  182.    {"ABOUT",            MENUID(ICON_MENU,IM_ABOUT,NOSUB)},
  183.    {"END",              MENUID(ICON_MENU,IM_END,NOSUB)},
  184.    {"TO_FRONT",         MENUID(SCREEN_MENU,SM_TOFRONT,NOSUB)},
  185.    {"TO_BACK",          MENUID(SCREEN_MENU,SM_TOBACK,NOSUB)},
  186.    {"WB_TO_FRONT",      MENUID(SCREEN_MENU,SM_WBTOFRONT,NOSUB)},
  187.    {"TOGGLE_TITLE",     MENUID(SCREEN_MENU,SM_TOGGLE,NOSUB)},
  188.    {"ICONIFY",          MENUID(SCREEN_MENU,SM_ICONIFY,NOSUB)},
  189.    {"NEWCLI",           MENUID(SCREEN_MENU,SM_NEWCLI,NOSUB)},
  190.    {"MAKE_WB",          MENUID(SCREEN_MENU,SM_MAKEWB,NOSUB)},
  191.    {"ACTIVE_SCREEN",    MENUID(SCREEN_MENU,SM_OPENWINDOW,OW_ACTIVESCRN)},
  192.    {"CURRENT_WB",       MENUID(SCREEN_MENU,SM_OPENWINDOW,OW_CURRENTWB)},
  193.    {"REAL_WB",          MENUID(SCREEN_MENU,SM_OPENWINDOW,OW_REALWB)},
  194.    {"SIZE_TO_FIT",      MENUID(SCREEN_MENU,SM_OPENWINDOW,OW_AUTORESIZE)},
  195.    {"HIRES",            MENUID(SCREEN_MENU,SM_NEWSCREEN,NS_HIRES)},
  196.    {"LORES",            MENUID(SCREEN_MENU,SM_NEWSCREEN,NS_LORES)},
  197.    {"INTERLACE",        MENUID(SCREEN_MENU,SM_NEWSCREEN,NS_INTERLACE)},
  198.    {"HAM",              MENUID(SCREEN_MENU,SM_NEWSCREEN,NS_HAM)},
  199.    {"CLOSE_SCREEN",     MENUID(SCREEN_MENU,SM_CLOSESCREEN,NOSUB)},
  200. };
  201. #define MAXMENU     25
  202.  
  203.  
  204.  
  205. /*
  206.  *  ReadCommand()
  207.  *
  208.  *  If we're at the end of the line, read the next line.
  209.  *  Get the next word on the line.
  210.  *  If we have readed the end of the file, use COM_EOF
  211.  *  Otherwise, if the character following the next word is not ':'
  212.  *    then we have not found a command, so use COM_NONE,
  213.  *  Otherwise,
  214.  *    Look for the command in the current command table, and skip the ':'
  215.  *  Return the number of the command found.
  216.  */
  217.  
  218. int ReadCommand()
  219. {
  220.    int Command = COM_UNKNOWN;
  221.    short i;
  222.  
  223.    if (NextChar == '\n' || NextChar == 0) ReadNextLine();
  224.    ReadNextWord();
  225.    if (EndOfFile)       Command = COM_EOF; else
  226.    if (NextChar != ':') Command = COM_NONE;
  227.    else
  228.    {
  229.       for (i=0; i<=ComCount && Command == COM_UNKNOWN; i++)
  230.          if (WORDMATCH(ComName[i])) Command = i + ComOffset;
  231.       SkipChar();
  232.    }
  233.    return(Command);
  234. }
  235.  
  236.  
  237. /*
  238.  *  ReadKeyDef()
  239.  *
  240.  *  Parse the next word as a qualifier or key name.
  241.  *  If theKey is NULL, no key name is allowed, if DisQual is NULL, no
  242.  *  disqualifiers are allowed.
  243.  *  
  244.  *  If the next character is '\' and we are accepting key names,
  245.  *    Go back to the start of the word and skip the '\'
  246.  *    If the next char is a HEX digit,
  247.  *      Get the HEX value of the next char and get the following char.
  248.  *      If the following char is a HEX digit,
  249.  *        Shift the old hex digit by 16 (10 HEX), add the next digit,
  250.  *        and get the next character
  251.  *      Skip any blanks.
  252.  *      Mark the code as a key-up event
  253.  *    Otherwise give an error message.
  254.  *    Indicate that this should be the end of the line.
  255.  *  Otherwise (not a '\')
  256.  *    If the word is '+' or '|', ie, a qualifier, then
  257.  *      If there were no qualifiers or disqualifiers given, give a message
  258.  *      Get the next word (the qualifier itself)
  259.  *    Otherwise, if the word is '-', ie, a disqualifier, then
  260.  *      Check to make sure disqualifiers are allowed; error if not.
  261.  *      Get the disqualifier.
  262.  *    Look through the qualifier flag names for a match.
  263.  *      If a match is found,
  264.  *        add the qualifier to the proper list and end the loop
  265.  *    If no qualifier was found,
  266.  *      If we are allowed to have a key name,
  267.  *        Go back to the beginning of the word, and re-read it allowing numbers
  268.  *        Look through the key name list
  269.  *          If a match is found,
  270.  *            Record the key number and end the loop.
  271.  *            Indicate that this should be the end of the line.
  272.  *        If no match found, give an error.
  273.  *      Otherwise (no key name allowed) give an error.
  274.  *  Return the end-of-line status.
  275.  */
  276.  
  277. int ReadKeyDef(theKey,theQual,DisQual)
  278. UBYTE *theKey;
  279. USHORT *theQual,*DisQual;
  280. {
  281.    short i;
  282.    int AddIt = TRUE;
  283.    int EndOfLine = FALSE;
  284.    int OpMissing;
  285.    
  286.    if (Word[0] == '\\' && theKey)
  287.    {
  288.       Reread(); GetNextChar();
  289.       if (HEXCHAR(NextChar))
  290.       {
  291.          *theKey = HEX(NextChar);
  292.          GetNextChar();
  293.          if (HEXCHAR(NextChar))
  294.          {
  295.             *theKey = 16*(*theKey) + HEX(NextChar);
  296.             GetNextChar();
  297.          }
  298.          SkipSpaces();
  299.          *theKey |= IECODE_UP_PREFIX;
  300.       } else Expected("HEX char");
  301.       EndOfLine = TRUE;
  302.    } else {
  303.       if (Word[0] == '+' || Word[0] == '|')
  304.       {
  305.          if (*theQual == 0)
  306.          {
  307.             if (DisQual == NULL) OpMissing = TRUE; else
  308.             if (*DisQual == 0)   OpMissing = TRUE; else OpMissing = FALSE;
  309.             if (OpMissing) ShowError("Missing Qualifier before '%c'",Word[0]);
  310.          }
  311.          ReadNextWord();
  312.       } else if (Word[0] == '-') {
  313.          if (DisQual) AddIt = FALSE; else
  314.             ShowError("Disqualifiers not allowed");
  315.          ReadNextWord();
  316.       }
  317.       for (i=0; i<MAXKEYFLAG; i++)
  318.       {
  319.          if (WORDMATCH(KeyFlag[i].Name))
  320.          {
  321.             if (AddIt) *theQual |= KeyFlag[i].Flag;
  322.                else    *DisQual |= KeyFlag[i].Flag;
  323.             i = MAXKEYFLAG+1;
  324.          }
  325.       }
  326.       if (i == MAXKEYFLAG)
  327.       {
  328.          if (theKey)
  329.          {
  330.             Reread(); ReadExtendedWord();
  331.             for (i=0; i<MAXKEYNAME; i++)
  332.             {
  333.                if (WORDMATCH(KeyName[i].Name))
  334.                {
  335.                   *theKey = KeyName[i].Flag;
  336.                   i = MAXKEYNAME+1;
  337.                   EndOfLine = TRUE;
  338.                }
  339.             }
  340.             if (i == MAXKEYNAME) Expected("a Key-Name or Qualifier");
  341.          } else Expected("a Qualifier");
  342.       }
  343.    }
  344.    return(EndOfLine);
  345. }
  346.  
  347.  
  348. /*
  349.  *  ReadColor()
  350.  *
  351.  *  If the color number is a valid one,
  352.  *    Go back to the beginning of the word and read it as a number.
  353.  *    Set it to upper case (for HEX check).
  354.  *    If the word is '=', set the color value to NOCOLOR
  355.  *    If the color is a valid color specification, get the color value
  356.  *    If the color is '*' leave the color alone,
  357.  *    Otherwise, give an error.
  358.  *  Otherwise give an error about how many colors are allowed.
  359.  */
  360.  
  361. void ReadColor(theID)
  362. short theID;
  363. {
  364.    extern UWORD *ScreenColors;
  365.  
  366.    if (theID < 32)
  367.    {
  368.       Reread(); ReadExtendedWord(); WordToUpper();
  369.       if (WORDMATCH("=")) ScreenColors[theID] = NOCOLOR; else
  370.       if (VALIDCOLOR(Word)) ScreenColors[theID] = COLOR(Word); else
  371.       if (WORDMATCH("*") == FALSE) Expected("an RGB Color");
  372.    } else ShowError("Maximum of 32 colors exceeded");
  373. }
  374.  
  375.  
  376. /*
  377.  *  ReadIconFlags()
  378.  *
  379.  *  If the word is '+' or '|', then
  380.  *    If there were no previous flags specified, give an error
  381.  *    The next word is the flag name
  382.  *  Look through the flag names
  383.  *    If one of them matches,
  384.  *      Add the flag to the default flags and end the loop
  385.  *  If no flag found, give an error.
  386.  */
  387.  
  388. void ReadIconFlags(Flags)
  389. long *Flags;
  390. {
  391.     short i;   
  392.     
  393.     if (Word[0] == '|' || Word[0] == '+')
  394.     {
  395.        if (*Flags == 0)
  396.           ShowError("Missing Icon Flag before '%c'",Word[0]);
  397.        ReadNextWord();
  398.     }
  399.     for (i=0; i<MAXICONFLAG; i++)
  400.     {
  401.        if (WORDMATCH(IconFlag[i].Name))
  402.           (*Flags) |= IconFlag[i].Flag,
  403.           i = MAXICONFLAG+1;
  404.     }
  405.     if (i == MAXICONFLAG) Expected("an Icon Flag");
  406. }
  407.  
  408.  
  409. /*
  410.  *  ReadMenuKey()
  411.  *
  412.  *  Look through the menu names
  413.  *    If one of them matches,
  414.  *      Get the pointer to the specified item in the menu bar structure;
  415.  *      If there is no command key, clear the COMSEQ flag for the item,
  416.  *      Otherwise,
  417.  *        Get the next word and make it upper case
  418.  *        If it is a control character, report an error;
  419.  *        If it is more than one characterm report an error;
  420.  *        Otherwise, set the command key to the indicated one.
  421.  *      End the loop.
  422.  *  If no match was found, give an error, and skip the rest of the line.
  423.  */
  424.  
  425. void ReadMenuKey()
  426. {
  427.    short i;  
  428.    struct MenuItem *theItem;
  429.    extern struct MenuItem *ItemAddress();
  430.    extern struct Menu *wMenuBar;
  431.    
  432.    for (i=0; i<MAXMENU; i++)
  433.    {
  434.       if (WORDMATCH(MenuName[i].Name))
  435.       {
  436.          theItem = ItemAddress(wMenuBar,MenuName[i].Flag);
  437.          if (NextChar == '\n')
  438.          {
  439.             theItem->Flags &= ~COMMSEQ;
  440.             theItem->Command = 0;
  441.          } else {
  442.             ReadNextWord(); WordToUpper();
  443.             if (Word[0] < ' ') Expected("a Printable Character"); else
  444.             if (Word[1] != 0)  Expected("a Single Character");
  445.             else theItem->Flags |= COMMSEQ, theItem->Command = Word[0];
  446.          }
  447.          i = MAXMENU+1;
  448.       }
  449.    }
  450.    if (i == MAXMENU)
  451.    {
  452.       if (strlen(Word) > 1) ShowError("Unrecognized Menu '%s'",Word);
  453.          else Expected("a Menu Item Name");
  454.       SkipLine();
  455.     }
  456. }
  457.  
  458.  
  459. /*
  460.  *  ReadBool()
  461.  *
  462.  *  If the word is "TRUE", return TRUE.
  463.  *  If the word is "FALSE", return FALSE.
  464.  *  Otherwise, give an error.
  465.  */
  466.  
  467. void ReadBool(n)
  468. int *n;
  469. {
  470.    if (WORDMATCH("TRUE"))  *n = TRUE; else
  471.    if (WORDMATCH("FALSE")) *n = FALSE; else
  472.       Expected("TRUE or FALSE");
  473. }
  474.  
  475.  
  476. /*
  477.  *  ReadInteger()
  478.  *
  479.  *  Parse the next word as an integer.
  480.  *  If the word is an integer, return it, otherwise give an error.
  481.  */
  482.  
  483. void ReadInteger(i)
  484. int *i;
  485. {
  486.    ReadNextInteger();
  487.    if (sscanf(Word,"%d",i) != 1) Expected("Integer value");
  488. }
  489.  
  490.  
  491. /*
  492.  *  ReadString()
  493.  *
  494.  *  Get the whole line as the next word.
  495.  *  If the character string has already been read, free it.
  496.  *  Get enough space for the new string, and copy the value into it.
  497.  *  Of not enough space, give an error.
  498.  */
  499.  
  500. void ReadString(s)
  501. char **s;
  502. {
  503.    ReadFullLine();
  504.    if (*s) FREECHAR(*s);
  505.    if (NEWCHAR(*s,strlen(Word))) strcpy(*s,Word); else
  506.       ShowError("Can't get memory for character string");
  507. }
  508.  
  509.  
  510. /*
  511.  *  ReadIgnoreScreen()
  512.  *
  513.  *  Get a new Ignore structure; if allocated OK,
  514.  *    Read the title of the screen.
  515.  *    If a title was found, add the screen to the ignored list,
  516.  *    Otherwise, free the Ignore structure.
  517.  *  Otherwise, give an error and skip the rest of the line.
  518.  */
  519.  
  520. void ReadIgnoreScreen()
  521. {
  522.    struct Ignore *theScreen;
  523.  
  524.    if (NEWSTRUCT(Ignore,theScreen))
  525.    {
  526.       ReadString(&theScreen->Title);
  527.       if (theScreen->Title)
  528.       {
  529.          theScreen->Next = IgnoreScreen;
  530.          IgnoreScreen = theScreen;
  531.       } else {
  532.          FREESTRUCT(Ignore,theScreen);
  533.       }
  534.    } else {
  535.       ShowError("Can't get memory to Ignore Screen");
  536.       SkipLine();
  537.    }
  538. }
  539.  
  540.  
  541. /*
  542.  *  GetPen()
  543.  *
  544.  *  Look for the given HEX digit in the extended HEX list.
  545.  *  If not found,
  546.  *    Give an error message and count the number of errors.
  547.  *    If more than the maximum allowed, skip the rest of the line.
  548.  *  If the image type is a MASK, and the pen is not 0 or 1,
  549.  *    If there were no previous errors of this type, give one.
  550.  *    Mark that the user was warned about mask pen types.
  551.  *    Reduce the pen number to 0 or 1.
  552.  *  Return the pen color.
  553.  */
  554.  
  555. static UBYTE GetPen(c)
  556. char c;
  557. {
  558.    UBYTE Pen = 0;
  559.    short i;
  560.  
  561.    for (i=0; i<32; i++) if (c == ExtHex[i]) Pen = i, i = 33;
  562.    if (i == 32)
  563.    {
  564.       Expected("HEX Digit"); ErrorCount++;
  565.       if (ErrorCount > MAXERROR)
  566.          printf("Maximum errors exceeded - skipping rest of line\n"),
  567.          SkipLine();
  568.    }
  569.    if (Pen > 1 && (ImageType == COM_DEFAULTMASK || ImageType == COM_SCREENMASK))
  570.    {
  571.       if (NoMaskError) ShowError("Mask pixel values must be 0 or 1");
  572.       NoMaskError = FALSE;
  573.       Pen = Pen & 1;
  574.    }
  575.    return(Pen);
  576. }
  577.  
  578.  
  579. /*
  580.  *  ReadImageLine()
  581.  *
  582.  *  If the current line is within the maximum image size,
  583.  *    Clear the error flags, and get back to the beginning of the line.
  584.  *    While we're not at the end of the line,
  585.  *      If the current column is within the maximum image size,
  586.  *        Get the pen number of the current pixel, and increment the column.
  587.  *        Update Plane0 and Plane1 (Plane0 has a zero wherever that plane
  588.  *          has at least one pixel that is zero; Plane1 has a 1 wherever
  589.  *          that plane has at least one pixel that is one).
  590.  *        If the bit mask has wrapped around, go on to the next image word.
  591.  *        For each 1 bit in the Pen color, add a 1 bit into the image data
  592.  *        Shift the image mask to the right.
  593.  *        Get the next pixel's pen color and skip any comments.
  594.  *        Skip trailing blanks (but not interior blanks).
  595.  *      Otherwise, indicate that the width is too large and skip to the
  596.  *        end of the line.
  597.  *    Update the current image size, if necessary.
  598.  *  Otherwise, indicate that the icon is too tall, and skip to the next line.
  599.  */
  600.  
  601. void ReadImageLine(y)
  602. short y;
  603. {
  604.    short x = 0, w = 0;
  605.    short d;
  606.    UWORD mask = BIT(15);
  607.    UBYTE Pen;
  608.    
  609.    if (y < MAXHEIGHT)
  610.    {
  611.       NoMaskError = TRUE; ErrorCount = 0;
  612.       Reread();
  613.       while (NextChar != '\n')
  614.       {
  615.          if (x < MAXWIDTH)
  616.          {
  617.             Pen = GetPen(NextChar); x++;
  618.             Plane0 &= Pen; Plane1 |= Pen; d = 0;
  619.             if (mask == 0) w++, mask = BIT(15);
  620.             while (Pen)
  621.             {
  622.                if (Pen & 1) ImageData[w][y][d] |= mask;
  623.                Pen >>= 1; d++;
  624.             }
  625.             mask >>= 1;
  626.             GetNextChar(); SkipComments();
  627.             if (NextChar == ' ')
  628.             {
  629.                SkipSpaces();
  630.                if (NextChar != '\n') Reread();
  631.             }
  632.          } else {
  633.             ReadFullLine();
  634.             ShowError("Maximum Image Width of %d exceeded",MAXWIDTH);
  635.          }
  636.       }
  637.       if (x   > MaxWidth)  MaxWidth = x, MaxWords = w+1;
  638.       if (y+1 > MaxHeight) MaxHeight = y+1;
  639.       if (MaxWidth > MAXWIDTH) MaxWidth = MAXWIDTH;
  640.    } else {
  641.       ReadFullLine();
  642.       ShowError("Maxmimum Image Height of %d exceeded",MAXHEIGHT);
  643.    }
  644. }
  645.  
  646.  
  647. /*
  648.  *  ReadIconFile()
  649.  *
  650.  *  Get the rest of the line (it will be the file name to open)
  651.  *  Save the current file information.
  652.  *  Attempt to open the specified file.
  653.  *  If openned OK, then
  654.  *    Set the icon file flag,
  655.  *    Set the command list to the icon file command list and size.
  656.  *  Otherwise,
  657.  *    Put back the old file information,
  658.  *    Give an error about the icon file.
  659.  */
  660.  
  661. void ReadIconFile(Offset)
  662. int Offset;
  663. {
  664.    ReadFullLine();
  665.    SaveOpenFile();
  666.    if (OpenFile(Word))
  667.    {
  668.       IconFileOpen = TRUE;
  669.       ComName = &IconCommand[0];
  670.       ComOffset = Offset;
  671.       ComCount = MAXICONCOM;
  672.    } else {
  673.       RestoreFile();
  674.       ShowError("Can't open Icon file '%s'",Word);
  675.    }
  676. }
  677.  
  678.  
  679. /*
  680.  *  EndIconFile()
  681.  *
  682.  *  Put back the old file information
  683.  *  Mark the file as closed, and restore the command list to the main list.
  684.  */
  685.  
  686. void EndIconFile()
  687. {
  688.    RestoreFile();
  689.    IconFileOpen = FALSE;
  690.    ComName = &MainCommand[0];
  691.    ComOffset = 0;
  692.    ComCount = MAXMAINCOM;
  693. }
  694.  
  695.  
  696. /*
  697.  *  ReadOpenOn()
  698.  *
  699.  *  Check if the word is one of "ACTIVE_SCREEN", "CURRENT_WB", or "REAL_WB",
  700.  *  and return the correct type, otherwise give an error.
  701.  */
  702.  
  703. void ReadOpenOn()
  704. {
  705.    if (WORDMATCH("ACTIVE_SCREEN"))  ScreenType = OW_ACTIVESCRN; else
  706.    if (WORDMATCH("CURRENT_WB"))     ScreenType = OW_CURRENTWB; else
  707.    if (WORDMATCH("REAL_WB"))        ScreenType = OW_REALWB; else
  708.       Expected("ACTIVE_SCREEN, CURRENT_WB, or REAL_WB");
  709. }
  710.